(define-module (polar)
  #:use-module (rnrs base)
  #:use-module ((guile) #:select (lambda* λ simple-format))
  #:use-module (tagged-data)
  #:use-module (math)
  #:export (make-from-real-imag
            make-from-mag-ang
            rectangular?
            data-tag
            real-part
            imag-part
            magnitude
            angle
            install-package))


(define data-tag 'polar)

  ;;; CONSTRUCTORS

(define make-from-real-imag
  (λ (real imag)
    (attach-tag data-tag
                (cons (sqrt (+ (square real)
                               (square imag)))
                      (atan imag real)))))

(define make-from-mag-ang
  (λ (mag ang)
    (attach-tag data-tag
                (cons mag ang))))

  ;;; ACCESSORS

(define magnitude
  (λ (num)
    (car num)))

(define angle
  (λ (num)
    (cdr num)))

(define real-part
  (λ (num)
    (simple-format #t "real-part in polar: ~a\n" num)
    (* (magnitude num)
       (cos (angle num)))))

(define imag-part
  (λ (num)
    (* (magnitude num)
       (sin (angle num)))))

(define polar?
  (λ (datum)
    (eq? (type-tag datum) data-tag)))


;; But actually ... it is currently the same for all packages! But
;; that would require the main module to know about all procedures
;; defined in each package or prescribe a common interface without
;; package specific additions. Package specific additiona would become
;; useless, if install package was generic. -- So lets keep it in the
;; package for now.
(define install-package
  (λ (lookup-table put)
    (let iter
        ([funcs° (list make-from-real-imag
                       make-from-mag-ang
                       rectangular?
                       data-tag
                       real-part
                       imag-part
                       magnitude
                       angle)])
      (cond
       [(null? funcs°) lookup-table]
       [else
        (put lookup-table op type func)
        (iter (cdr funcs°))]))))
